home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / mus / play / tracker_4_31.lzh / tracker / Amiga / client.c < prev    next >
C/C++ Source or Header  |  1995-02-14  |  7KB  |  300 lines

  1. /* amiga/client.c 
  2.     vi:ts=3 sw=3:
  3.  */
  4.  
  5. /* $Id: client.c,v 1.10 1995/02/14 16:51:22 espie Exp espie $
  6.  * $Log: client.c,v $
  7.  * Revision 1.10  1995/02/14  16:51:22  espie
  8.  * *** empty log message ***
  9.  *
  10.  * Revision 1.9  1995/01/13  13:31:35  espie
  11.  * *** empty log message ***
  12.  *
  13.  * Revision 1.7  1994/01/08  19:45:29  Espie
  14.  * Uncentralized event handling using event management functions.
  15.  * Priority lowered.
  16.  * Added check_type call for non-blocking processing.
  17.  * Fully working asynchronous interface.
  18.  */
  19.  
  20. /* client to the audio server */
  21.  
  22.  
  23. #include <exec/types.h>
  24. #include <exec/tasks.h>
  25. #include <exec/memory.h>
  26. #include <exec/ports.h>
  27.  
  28. #include <proto/exec.h>
  29.  
  30.  
  31. #include "defs.h"
  32. #include "extern.h"
  33. #include "song.h"
  34. #include "amiga/amiga.h"
  35.  
  36. ID("$Id: client.c,v 1.10 1995/02/14 16:51:22 espie Exp espie $")
  37. XT unsigned int inhibit_output;
  38.  
  39. LOCAL void init_client(void);
  40. LOCAL void (*INIT)(void) = init_client;
  41.  
  42. #define STACK_SIZE 4000
  43. #define HIPRI 50     /* should be higher than intuition's */
  44. #define SUBNAME "Tracker sound server"
  45.  
  46. LOCAL struct MsgPort *subport = 0;
  47.  
  48. LOCAL struct MsgPort *myport = 0;
  49.  
  50. LOCAL struct ext_message *chunk = 0;
  51.  
  52. LOCAL struct MinList buffer;
  53. LOCAL int live_task = FALSE;
  54. LOCAL int watched_type = TYPE_INVALID; 
  55. LOCAL struct ext_message *watched_message;
  56.  
  57. LOCAL void handle_subtask_events(GENERIC nothing)
  58.    {
  59.    struct ext_message *msg;
  60.    
  61.    while (msg = GetMsg(myport))
  62.       {
  63.       if (msg->type == TYPE_SYNC_DO)
  64.          (msg->data.hook.func)(msg->data.hook.p);
  65.       AddTail(&buffer, msg);
  66.       if (msg->type == watched_type)
  67.          {
  68.          watched_message = msg;
  69.          watched_type = TYPE_INVALID;
  70.          }
  71.       }
  72.    }
  73.  
  74. struct ext_message *obtain_message()
  75.    {
  76.    struct ext_message *msg;
  77.    
  78.    INIT_ONCE;
  79.  
  80.    forever
  81.       {
  82.          /* get messages from port first: best synchronization */
  83.       check_events();
  84.             /* message available ? */
  85.       if (msg = RemHead(&buffer))
  86.          return msg;
  87.       else  /* no-> wait for one */
  88.          await_events();
  89.       }
  90.    }
  91.  
  92.  
  93. void send(struct ext_message *msg, int type)
  94.    {
  95.       /* valid only for messages obtained through obtain_message ! */
  96.    msg->type = type;
  97.    msg->msg.mn_ReplyPort = myport;
  98.    PutMsg(subport, msg);
  99.    }
  100.  
  101.  
  102. struct ext_message *check_type(int type)
  103.    {
  104.    struct ext_message *msg;
  105.  
  106.    watched_type = type;
  107.    check_events();
  108.    if (watched_message)
  109.       {
  110.       msg = watched_message;
  111.       watched_message = 0;
  112.       return msg;
  113.       }
  114.    else
  115.       return 0;
  116.    }
  117.    
  118. /* Note that await_type returns a message for checking purposes.
  119.  * This message is NOT available
  120.  */
  121. struct ext_message *await_type(int type)
  122.    {
  123.    struct ext_message *msg;
  124.  
  125.    forever
  126.       {
  127.       watched_type = type;
  128.       check_events();
  129.       if (watched_message)
  130.          {
  131.          msg = watched_message;
  132.          watched_message = 0;
  133.          return msg;
  134.          }
  135.       await_events();
  136.       }
  137.    }
  138.  
  139. LOCAL void kill_subtask()
  140.    {
  141.    struct ext_message *msg;
  142.       /* tell the subtask to die */
  143.    msg = obtain_message();
  144.    send(msg, TYPE_DIE);
  145.       /* and wait for it to be in a dying state (Wait(0)) */
  146.    msg = await_type(TYPE_DIE);
  147. #ifndef EXTERNAL
  148.       /* then kill it */
  149.    RemTask(msg->data.comm.task);
  150. #endif
  151.    live_task = FALSE;
  152.    }
  153.  
  154.  
  155.  
  156. LOCAL struct Task *newtask = 0;
  157. LOCAL void *stack = 0;
  158.  
  159. /* We build up the task structure by ourselves. That way, we can
  160.  * easily pass a message around by pushing it on the stack
  161.  */
  162. LOCAL void create_subtask()
  163.    {
  164.    ULONG *p;
  165.    struct ext_message *msg;
  166.  
  167. #ifdef EXTERNAL
  168.       /* we just have to find the task */
  169.    struct MsgPort *pubport;
  170.  
  171.    pubport = FindPort(PUBLIC_PORT_NAME);
  172.    if (!pubport)
  173.       end_all("Could not rendez-vous");
  174.       /* it's there: get it in working order */
  175.    msg = obtain_message();
  176.    msg->type = TYPE_COMM;
  177.    msg->msg.mn_ReplyPort = myport;
  178.    PutMsg(pubport, msg);
  179.    msg = await_type(TYPE_COMM);
  180.       /* check it's running correctly */
  181.    if (msg->data.comm.port)
  182.       {
  183.       subport = msg->data.comm.port;
  184.       live_task = TRUE;
  185.       }
  186.    else
  187.       {
  188.       end_all("subtask creation failed");
  189.       }
  190. #else
  191.       /* build the new task from scratch */
  192.    newtask = AllocVec(sizeof(struct Task), MEMF_CLEAR | MEMF_PUBLIC);
  193.    if (!newtask)
  194.       end_all("No task struct");
  195.    stack = AllocVec(STACK_SIZE, MEMF_CLEAR);
  196.    if (!stack)
  197.       end_all("No stack");
  198.    newtask->tc_SPLower = stack;
  199.    newtask->tc_SPUpper = (APTR)((ULONG)(newtask->tc_SPLower) + STACK_SIZE);
  200.    newtask->tc_Node.ln_Type = NT_TASK;
  201.    newtask->tc_Node.ln_Pri = HIPRI;
  202.    newtask->tc_Node.ln_Name = SUBNAME;
  203.  
  204.       /* ready to run: set it up for answering */      
  205.    msg = obtain_message();
  206.    msg->type = TYPE_COMM;
  207.    msg->msg.mn_ReplyPort = myport;
  208.       /* push message on the stack */
  209.    p = newtask->tc_SPUpper;
  210.    *(--p) = (ULONG)msg;
  211.    newtask->tc_SPReg = p;
  212.    
  213.    if (!AddTask(newtask, subtask, 0))
  214.       end_all("No subtask");
  215.       /* Check it started up okay */
  216.    msg = await_type(TYPE_COMM);
  217.    if (msg->data.comm.port)
  218.       {
  219.       subport = msg->data.comm.port;
  220.       live_task = TRUE;
  221.       }
  222.    else
  223.       {
  224.       RemTask(msg->data.comm.task);
  225.       end_all("subtask creation failed");
  226.       }
  227. #endif
  228.    }
  229.  
  230.  
  231. /* right now, messages are statically allocated.
  232.  * It might be a good idea to start with a SMALL
  233.  * fixed number of messages (say 50) and increase
  234.  * the queue on timing faults. A bit tricky, though.
  235.  */
  236. LOCAL void alloc_messages()
  237.    {
  238.    int i;
  239.    
  240.    myport = CreateMsgPort();
  241.    if (!myport)
  242.       end_all("Couldn't open message port");
  243.    install_signal_handler(myport->mp_SigBit, handle_subtask_events, 0);
  244.    chunk = AllocVec(sizeof(struct ext_message) * BUFFER_SIZE, MEMF_PUBLIC | MEMF_CLEAR);
  245.    if (!chunk)
  246.       end_all("Message allocation failed");
  247.    for (i = 0; i < BUFFER_SIZE; i++)
  248.       {
  249.          /* don't forget this ! */
  250.       chunk[i].msg.mn_Node.ln_Type = NT_MESSAGE;
  251.       chunk[i].msg.mn_Length = sizeof(struct ext_message);
  252.       AddTail(&buffer, chunk+i);
  253.       }
  254.    }
  255.  
  256. LOCAL void end_client()
  257.    {
  258.    if (live_task)
  259.       kill_subtask();
  260.       /* note that the subtask is already dead when end_client is called */
  261.    if (chunk)
  262.       FreeVec(chunk);
  263.    if (newtask)
  264.       FreeVec(newtask);
  265.    if (stack)
  266.       FreeVec(stack);
  267.    if (myport)
  268.       {
  269.       remove_signal_handler(myport->mp_SigBit);
  270.       DeleteMsgPort(myport);
  271.       }
  272.    }
  273.       
  274. LOCAL void init_client()
  275.    {
  276.    NewList(&buffer);
  277.    at_end(end_client);
  278.    alloc_messages();    /* note we must call alloc_messages BEFORE create_subtask
  279.                          * since create_subtask depends on obtain_message
  280.                          */
  281.    create_subtask();    /* this hooks kill_subtask, AFTER end_client,
  282.                          * so it will be called BEFORE.
  283.                          */
  284.    }
  285.  
  286. void close_audio(void)
  287.    {
  288.    if (live_task)
  289.       {
  290.       struct ext_message *msg;
  291.  
  292.       msg = obtain_message();
  293.       msg->data.info.channel_mask = 15;
  294.       send(msg, TYPE_FLUSH_CHANNEL);
  295.       while (msg != await_type(TYPE_FLUSH_CHANNEL))
  296.          ;
  297.       }
  298.    }
  299.  
  300.